-------------------------------------------------------------------------------------------------------------
-- Project   : IF Clock generator Project
-- Filename  : dig_core_adpll.vhd
-- Content   : Implementation of digital core of the ADPLL
-- Version   : -
-- Author    : Gijs Meuleman (gijs.meuleman@imec-nl.nl)
-- Copyright : Stichting Imec Nederland (http://www.imec-nl.nl)
-------------------------------------------------------------------------------------------------------------

-- libraries ------------------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity dig_core_adpll is
   port ( 	
		fcw_i 		: in  std_logic_vector(7 downto 0);	-- integer part frequency control word
		fcw_f 		: in  std_logic_vector(4 downto 0);	-- fractional part frequency control word
		int_offset 	: in  std_logic;   						-- fixed offset control (for int. mult.)
		alpha			: in  std_logic_vector(3 downto 0);	-- gain alpha (shift operation)
		rho			: in  std_logic_vector(4 downto 0);	-- gain rho (shift operation)
		ckdiv_en		: in  std_logic;							-- enable output dither clock
		ckdiv			: in  std_logic_vector(7 downto 0);	-- ckv division factor
		sel_df_spi	: in  std_logic;							-- select control of fine dac via spi
		df_spi		: in  std_logic_vector(4 downto 0);	-- control word for fine dac via spi
		ctrl_en_spi	: in  std_logic;							-- enable spi control signals to latch 
																		-- to ADPLL blocks (avoids metastabilit
		rstn			: in  std_logic;							-- reset, active low
		ckv			: in  std_logic;							-- 20 MHz input clock for dither freq.
		ckr			: in  std_logic;							-- retimed reference clock
		phv_f 		: in  std_logic_vector(4 downto 0);	-- fractional part variable phase input
		en_sdm		: in  std_logic;							-- enable (1) or disable (0) SDM
		df				: out std_logic_vector(4 downto 0);	-- control word for the fine tuning DAC
		ckdiv16e		: out std_logic;							-- clock signal for the fine tuning DAC
		ctrl_enable	: out std_logic;							-- control enable signal, can be wired 
																		-- to I/O pin and be used as trigger.
		test_phe_i	: out std_logic_vector(7 downto 0);
		test_tune_i	: out std_logic_vector(4 downto 0);
		test_phe_f	: out std_logic_vector(4 downto 0)
	);
end entity dig_core_adpll;

architecture rtl of dig_core_adpll is
-- components -----------------------------------------------------------------------------------------------
	component phase_detector
	port (
		rstn 				: in  std_logic;
		ckr 				: in  std_logic;
		ckv 				: in  std_logic;
		phv_f 			: in  std_logic_vector(4 downto 0);
		fcw_i 			: in  std_logic_vector(7 downto 0);
		fcw_f 			: in  std_logic_vector(4 downto 0);
		int_offset 		: in  std_logic;          
		phe_i 			: out std_logic_vector(11 downto 0);
		phe_f 			: out std_logic_vector(9 downto 0);
		test_phe_f		: out std_logic_vector(4 downto 0)
	);
	end component;

	component loop_filter
	port ( 
		rstn				: in  std_logic;							
      ckr  				: in  std_logic;							
      phe_i 			: in  std_logic_vector(11 downto 0);	
		phe_f				: in  std_logic_vector(9 downto 0);	
		alpha				: in  std_logic_vector(3 downto 0);	
		rho				: in  std_logic_vector(4 downto 0);	
		tune_i	 		: out std_logic_vector(4 downto 0); 
		tune_f			: out std_logic_vector(9 downto 0)	
	);
	end component;
	
	component dac_control
	port (
		rstn 				: in  std_logic;
		ckv 				: in  std_logic;
		tune_i 			: in  std_logic_vector(4 downto 0);
		tune_f 			: in  std_logic_vector(9 downto 0);
		ckdiv_en			: in  std_logic;
		ckdiv 			: in  std_logic_vector(7 downto 0);
		sel_df_spi		: in  std_logic;
		df_spi 			: in  std_logic_vector(4 downto 0);          
		en_sdm			: in  std_logic;
		df 				: out std_logic_vector(4 downto 0);
		ckdiv16e 		: out std_logic
	);
	end component;

-- signals --------------------------------------------------------------------------------------------------
	signal s_phe_i						: std_logic_vector(11 downto 0) := (others => '0');
	signal s_phe_f 					: std_logic_vector(9 downto 0) := (others => '0');
	signal s_tune_i 					: std_logic_vector(4 downto 0) := (others => '0');
	signal s_tune_f 					: std_logic_vector(9 downto 0) := (others => '0');
	signal s_spi_ctrl_en_delayed	: std_logic := '0';
	signal s_latched_fcw_i 			: std_logic_vector(7 downto 0) := (others => '0');	
	signal s_latched_fcw_f 			: std_logic_vector(4 downto 0) := (others => '0');	
	signal s_latched_int_offset 	: std_logic := '0';   						
	signal s_latched_alpha			: std_logic_vector(3 downto 0) := (others => '0');	
	signal s_latched_rho				: std_logic_vector(4 downto 0) := (others => '0');	
	signal s_latched_ckdiv_en		: std_logic := '0';							
	signal s_latched_ckdiv			: std_logic_vector(7 downto 0) := (others => '0');	
	signal s_latched_sel_df_spi	: std_logic := '0';							
	signal s_latched_df_spi			: std_logic_vector(4 downto 0) := (others => '0');
	signal s_latched_rstn			: std_logic := '0';
begin
	i_phase_detector: phase_detector port map(
		rstn => s_latched_rstn,
		ckr => ckr,
		ckv => ckv,
		phv_f => phv_f,
		fcw_i => s_latched_fcw_i,
		fcw_f => s_latched_fcw_f,
		int_offset => s_latched_int_offset,
		phe_i => s_phe_i,
		phe_f =>	s_phe_f,
		test_phe_f => test_phe_f
	);
	
	i_loop_filter: loop_filter port map(
		rstn => s_latched_rstn,
		ckr => ckr,
		phe_i => s_phe_i,
		phe_f => s_phe_f,
		alpha => s_latched_alpha,
		rho => s_latched_rho,
		tune_i => s_tune_i,
		tune_f => s_tune_f
	);
	
	i_dac_control: dac_control port map(
		rstn => s_latched_rstn,
		ckv => ckv,
		tune_i => s_tune_i,
		tune_f => s_tune_f,
		ckdiv_en => s_latched_ckdiv_en,
		ckdiv => s_latched_ckdiv,
		sel_df_spi => s_latched_sel_df_spi,
		df_spi => s_latched_df_spi,
		en_sdm => en_sdm,
		df => df,
		ckdiv16e => ckdiv16e
	);
	
	-- test signals
	test_phe_i <= s_phe_i(7 downto 0);
	test_tune_i <= s_tune_i;
	
	-- latch the spi control signals after flip flop delayed enable signal (prevents metastability problems)
	p_spi_ctrl_en : process (ckr) is
	begin
		if rising_edge(ckr) then
			-- latch spi control signals to ADPLL blocks when delayed enable signal is '1'
			if s_spi_ctrl_en_delayed = '1' then
				s_latched_fcw_i <= fcw_i;	
				s_latched_fcw_f <= fcw_f;	
				s_latched_int_offset <= int_offset; 						
				s_latched_alpha <= alpha;	
				s_latched_rho <= rho;
				s_latched_ckdiv_en <= ckdiv_en;							
				s_latched_ckdiv <= ckdiv;	
				s_latched_sel_df_spi	<= sel_df_spi;							
				s_latched_df_spi <= df_spi;
				s_latched_rstn <= rstn;
			end if;
			-- update the delayed control enable signal
			s_spi_ctrl_en_delayed <= ctrl_en_spi;
			ctrl_enable <= ctrl_en_spi;
		end if;
	end process;
end rtl;
